package cn.com.dcsgo.filter;

import cn.com.dcsgo.constant.AuthConstant;
import cn.com.dcsgo.model.SecurityUser;
import com.alibaba.fastjson2.JSON;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 自定义请求过滤器，用于解析token并将token中的用户信息存入SecurityContextHolder中
 *
 * @author Dcsgo
 * @since 2025/9/20 10:26
 */
@Component
public class TokenTranslateFilter extends OncePerRequestFilter {
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String authorization = request.getHeader(AuthConstant.AUTHORIZATION);
        if (StringUtils.hasText(authorization)) {
            String token = authorization.replaceFirst(AuthConstant.BEARER, ""); // 提取纯 Token（去掉 "Bearer " 前缀）

            // 2. 检查 Token 是否在 Redis 中存在（用户登录后其认证信息存储在Redis中）
            String key = AuthConstant.LOGIN_TOKEN_PREFIX + token;
            if (StringUtils.hasText(token) && stringRedisTemplate.hasKey(key)) {
                // 3. Token 即将过期时，自动续期（延长 Redis 中 Token 的过期时间）
                Long expire = stringRedisTemplate.getExpire(key);
                if (expire <= AuthConstant.TOKEN_EXPIRE_THRESHOLD_TIME) {
                    stringRedisTemplate.expire(key, AuthConstant.TOKEN_TIME, TimeUnit.SECONDS);
                }

                // 4. 从 Redis 获取用户信息（JSON 字符串转成 SecurityUser 对象）
                String jsonUser = stringRedisTemplate.opsForValue().get(key);
                SecurityUser securityUser = JSON.parseObject(jsonUser, SecurityUser.class);

                // 5. 构建用户权限（将用户的权限字符串转成 Spring Security 可识别的格式）
                Set<String> perms = securityUser.getPerms();
                Set<SimpleGrantedAuthority> authorities = perms.stream()
                        .map(SimpleGrantedAuthority::new)
                        .collect(Collectors.toSet());

                // 6. 将用户信息和权限存入“安全上下文”（Spring Security 后续会通过这里的信息判断用户是否认证/授权）
                UsernamePasswordAuthenticationToken tokenAuth =
                        UsernamePasswordAuthenticationToken.authenticated(securityUser, null, authorities);
                SecurityContextHolder.getContext().setAuthentication(tokenAuth);
            }
        }
        // 继续执行后续过滤器（如 Spring 自带的权限校验过滤器）
        filterChain.doFilter(request, response);
    }
}